﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Markup;
using System.Reactive.Concurrency;

using agree.schema;

using alib;
using alib.Enumerable;
using alib.Collections;
using alib.Debugging;

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("Count:{Count}")]
	public class Workspace : namescope_helper, IWorkspace, IActiveObj<IIdentity>,
		ρρDefaultDirectories,
		ρρName
	{
		public Workspace(IRtParent parent, String name)
		{
			this.parent = parent;
			this.name = name;
			this.dps = new DirectoryPathSet(this);
			this.tc = parent.TaskControl;
		}
		public Workspace(IRtParent parent)
			: this(parent, default(String))
		{
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		protected readonly IRtParent parent;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public IRtParent Parent { [DebuggerStepThrough] get { return parent; } }

		[DebuggerDisplay("{_identity_extensions._dbg_trace(this),nq}")]
		public IIdentity Trace { [DebuggerStepThrough] get { return parent; } }

		String name;
		public String Name
		{
			get { return this.name; }
			set { this.name = value; }
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		DirectoryPathSet dps;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public DirectoryPathSet DefaultDirectories
		{
			get { return dps; }
			set
			{
				if (value == null || value.Count == 0)
					return;
				if (dps.Count > 0)
					throw not.impl;
				dps = value;
			}
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		TaskController tc;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public TaskController TaskControl { get { return tc; } }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public INameScope NameScope { get { return this; } }

		public Object GetService(System.Type Tsvc)
		{
			return this.GetType().IsAssignableFrom(Tsvc) ? this : null;
		}

		IObserver<IIdentity>[] observers;

		IDisposable IObservable<IIdentity>.Subscribe(IObserver<IIdentity> obs)
		{
			var _tmp = items;
			if (_tmp != null)
			{
				// tmp tmp fix fix ... items can be missed during the transition
				for (int i = 0; i < _tmp.Length; i++)
					obs.OnNext(_tmp[i]);
			}

			alib.Array.arr.AppendSafe(ref observers, obs);
			return new _disposer(this, obs);
		}

		public void Add(IIdentity item)
		{
			alib.Array.arr.AppendSafe(ref items, item);

			var _tmp = observers;
			if (_tmp == null)
			{
				//Debug.Print("warning: item '[{0}] {1}' might be missed because workspace has no observer. Subscription should not be deferred to (e.g.) WPF dispatcher context.",
				//	 PP.Name.GetValue(item) ?? "no name",
				//	 item.GetType().Name);
			}
			else
				for (int i = 0; i < _tmp.Length; i++)
					_tmp[i].OnNext(item);
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		protected IIdentity[] items;
		public IIdentity[] ItemsArr { get { return items ?? Collection<IIdentity>.None; } set { throw not.valid; } }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public int Count { get { var _tmp = items; return _tmp == null ? 0 : _tmp.Length; } }

		public IIdentity this[int index] { get { return items[index]; } }

		public bool Contains(IIdentity item)
		{
			var _tmp = items;
			if (_tmp != null)
				for (int i = 0; i < _tmp.Length; i++)
					if (_tmp[i] == item)
						return true;
			return false;
		}

		void ICollection.CopyTo(Array array, int index)
		{
			var _tmp = items;
			if (_tmp != null)
				for (int i = 0; i < _tmp.Length; i++)
					array.SetValue(_tmp[i], index++);
		}

		public IEnumerator<IIdentity> GetEnumerator() { return ItemsArr.Enumerator(); }

		IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }

		bool ICollection.IsSynchronized { get { return false; } }

		Object ICollection.SyncRoot { get { return this; } }

		sealed class _disposer : IDisposable
		{
			public _disposer(Workspace wksp, IObserver<IIdentity> obs)
			{
				this.wksp = wksp;
				this.obs = obs;
			}
			readonly Workspace wksp;
			readonly IObserver<IIdentity> obs;
			public void Dispose() { alib.Array.arr.RemoveSafe(ref wksp.observers, obs); }
		};
	};
}
